package main

import (
    "sync"
    "fmt"
    "time"
    "container/list"
    "os"
)

var GLogQueue = list.New()
var GLogQueueLock = sync.Mutex{}

type RLogBuf struct {
    Logger  *RLog
    Time    time.Time
    Buf     []byte
}

type RLog struct {
    Writer  *os.File
    File    string
}

func newRLog(file string) *RLog {
    log := &RLog{File:file}
    w, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
    if err != nil {
        mainLog.Println("open log file failed.", file, err)
        return log
    }
    log.Writer = w
    return log
}

func (log *RLog) Printf(format string, v ...interface{}) {
    str := fmt.Sprintf(format, v...)
    buf := RLogBuf{Logger:log, Time:time.Now(), Buf:[]byte(str)}
    
    GLogQueueLock.Lock()
    GLogQueue.PushBack(&buf)
    GLogQueueLock.Unlock()
}

func (log *RLog) Println(a ...interface{}) {
    str := fmt.Sprintln(a...)
    buf := RLogBuf{Logger:log, Time:time.Now(), Buf:[]byte(str)}
    
    GLogQueueLock.Lock()
    GLogQueue.PushBack(&buf)
    GLogQueueLock.Unlock()
}

func (log *RLog) write(buf *RLogBuf) {
    if log.Writer == nil {
        return
    }
    
    if _, err := os.Stat(log.File); os.IsNotExist(err) {
        log.Writer.Close()
        log.Writer,_ = os.OpenFile(log.File, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644)
    }
    
    header := buf.Time.Format("[2006/01/02 15:04:05.000] ")
    log.Writer.Write([]byte(header))
    log.Writer.Write(buf.Buf)
}


func RLogRun() {
    run := func() {
        for {
            bufList := make([]*RLogBuf, 0)
            GLogQueueLock.Lock()
            for ; GLogQueue.Len() != 0; {
                buf := GLogQueue.Remove(GLogQueue.Front()).(*RLogBuf)
                bufList = append(bufList, buf)
                if len(bufList) > 10000 {
                    break
                }
            }
            GLogQueueLock.Unlock()
            
            if len(bufList) == 0 {
                time.Sleep(time.Second)
                continue
            }
            
            for i := 0; i < len(bufList); i++ {
                bufList[i].Logger.write(bufList[i])
            }
        }
    }
    
    go run()
}

var GRLogS = make(map[string]*RLog)
var GRLogSLock = sync.Mutex{}
func openRLog(file string) *RLog {
    GRLogSLock.Lock()
    log, ok := GRLogS[file]
    if !ok {
        log = newRLog(file)
        GRLogS[file] = log
    }
    GRLogSLock.Unlock()
    
    return log
}